#ifndef NANE_OALSOUNDSOURCE_H
#   define  NANE_OALSOUNDSOURCE_H

#   include "nane/SoundSystem/ISoundSystem.h"
#   include "nane/SoundSystem/OAL/OpenALAPI.h"
#   include "nane/SoundSystem/OAL/OALSoundBuffer.h"

#   include "nane/core/log.h"

namespace nane 
{
    struct OALSoundSource
        : public ISoundSource3D
    {
        ALuint source;
        std::vector<ISoundBuffer*> buffers;
        
        OALSoundSource()
            : source( 0 )
        {
            
        }

        virtual void Play( uint32 _posMs )
        {
            if( buffers.size() == 1 )
            {
                OALSoundBuffer* oalSoundBuffer = static_cast<OALSoundBuffer*>(buffers[0]);
                OpenALAPI::alSourcei(source, AL_BUFFER, oalSoundBuffer->bufferID);
                if( ALenum error = OpenALAPI::alGetError() )
                {
                    LOG_ERROR("Error while queueing OAL buffer (%1)") << OpenALAPI::alGetString(error);
                }
            }
            else
            {
                for( uint32 i = 0; i < buffers.size(); ++i )
                {
                    OALSoundBuffer* oalSoundBuffer = static_cast<OALSoundBuffer*>(buffers[i]);
                    OpenALAPI::alSourceQueueBuffers(source, 1, &oalSoundBuffer->bufferID);
                    if( ALenum error = OpenALAPI::alGetError() )
                    {
                        LOG_ERROR("Error while queueing OAL buffer (%1)") << OpenALAPI::alGetString(error);
                    }
                }
            }

            OpenALAPI::alSourcef(source, AL_SEC_OFFSET, static_cast<ALfloat>(_posMs) * 0.001f);
            if( ALenum error = OpenALAPI::alGetError() )
            {
                LOG_ERROR("Failed to set playback offset (%1)") << OpenALAPI::alGetString(error);
            }

            OpenALAPI::alSourcePlay(source);
            if( ALenum error = OpenALAPI::alGetError() )
            {
                LOG_ERROR("Error while playing OAL source (%1)") << OpenALAPI::alGetString(error);
            }
        }
    };

    struct OALSoundSource3D
        : public OALSoundSource
    {
        float x, y, z;
        float vx, vy, vz;

        OALSoundSource3D()
            : OALSoundSource()
            , x( 0.0f ), y( 0.0f ), z( 0.0f )
            , vx( 0.0f ), vy( 0.0f ), vz( 0.0f )
        {

        }

        void Play( uint32 _posMs )
        {
            OpenALAPI::alSource3f(source, AL_POSITION, x, y, z);
            if( ALenum error = OpenALAPI::alGetError() )
            {
                LOG_ERROR("Failed to set source 3D position (%1)") << OpenALAPI::alGetString(error);
            }

            OpenALAPI::alSource3f(source, AL_VELOCITY, vx, vy, vz);
            if( ALenum error = OpenALAPI::alGetError() )
            {
                LOG_ERROR("Failed to set source 3D velocity (%1)") << OpenALAPI::alGetString(error);
            }

            OALSoundSource::Play(_posMs);
        }
    };
}   // namespace nane

#endif	// NANE_OALSOUNDSOURCE_H
